package demo1;

import org.junit.Test;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;

/**
 * 一：通道：用于源节点与目标节点的连接
 * 在javaNIO中主要负责缓冲区中的数据传输，通道本身不存储任何数据，因此channel需要配合缓冲区完成传输工作
 * <p>
 * <p>
 * 二：通道的主要实现类
 * 在 java.nio.channels.Channel接口
 * <p>
 * <p>
 * 三：获取通道
 * 1.Java针对支持通道的类提供了getChannel方法
 * 2.在jdk1.7 以后的NIO（NIO2）针对各个通道提供了一个静态方法  open（）
 * 3.jdk1.7中的NIO2 files工具类的newByteChannel方法也可以获取通道
 * <p>
 * <p>
 * 四：通道之间的数据传输
 * transferFrom（）
 * transferTo（）
 * <p>
 * <p>
 * 五：分散（scatter）与聚集（gather）
 * 分散读取 （Scattering Reads）：将通道中的数据分散到多个缓冲区中
 * 聚集写入 （Gathering Writes）：将多个缓冲区的数据聚集到一个通道中
 *
 *
 * 六：字符集 CharSet
 * 编码：字符串->字节数组
 * 解码：字节数组->字符串
 *
 *
 */

public class TestChannel {

    /**
     * 字符集
     * CharSet
     * @throws IOException
     */
    @Test
    public void test5(){
        Map<String, Charset> map = Charset.availableCharsets();
        Set<Map.Entry<String, Charset>> entries = map.entrySet();

        for (Map.Entry<String,Charset> entry:
                entries
             ) {
            System.out.println(entry.getKey()+" ---- > "+entry.getValue());

        }

    }



    @Test
    public void test4() throws IOException {
        RandomAccessFile randomAccessFile = new RandomAccessFile("D:\\3\\D106623_GatedSA_OSEM.dcm.jpg", "rw");
        FileChannel inChannel = randomAccessFile.getChannel();
        ByteBuffer bf1 = ByteBuffer.allocate(100);
        ByteBuffer bf2 = ByteBuffer.allocate(1024);
        ByteBuffer bf3 = ByteBuffer.allocate(1024);
        ByteBuffer bf4 = ByteBuffer.allocate(2048);
        ByteBuffer[] bts = {bf1, bf2, bf3, bf4};
        inChannel.read(bts);
        for (ByteBuffer b :
                bts) {
            b.flip();
        }
        RandomAccessFile raf = new RandomAccessFile("D:\\3\\1111D106623_GatedSA_OSEM.dcm.jpg", "rw");
        FileChannel outChannel = raf.getChannel();
        outChannel.write(bts);
        outChannel.close();
        inChannel.close();


    }

    /**
     * 通道之间的数据传输
     */
    @Test
    public void test3() throws IOException {
        FileChannel inChannel = FileChannel.open(Paths.get("D:\\3\\D106623_GatedSA_OSEM.dcm.jpg"), StandardOpenOption.READ);
        FileChannel outChannel = FileChannel.open(Paths.get("D:\\3\\1111D106623_GatedSA_OSEM.dcm.jpg"), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        long l = inChannel.transferTo(0, inChannel.size(), outChannel);
        inChannel.close();
        outChannel.close();
    }


    /**
     * 使用直接缓冲区，使用内存映射
     * 直接缓冲区只有ByteBuffer支持
     */
    @Test
    public void test2() throws IOException {
        FileChannel inChannel = FileChannel.open(Paths.get("D:\\1\\2.jpg"), StandardOpenOption.READ);
        /**
         * StandardOpenOption.CREATE        存在这个文件将会覆盖
         *
         * StandardOpenOption.CREATE_NEW    存在这个文件将会报错，提示我们这个文件已经存在，会报错
         */
        FileChannel outChannel = FileChannel.open(Paths.get("D:\\1\\1.jpg"), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW);

        /**
         * mode  映射模式  READ_ONLY 只读模式  READ_WRITE
         * position 起始位置
         * 大小
         */

        //内存映射文件
        MappedByteBuffer inMapbuffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
        MappedByteBuffer outMapBuffer = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());

        //直接对缓冲区进行数据的读写操作
        byte[] dst = new byte[74 * 1024];
        inMapbuffer.get(dst);
        outMapBuffer.put(dst);
        inChannel.close();
        outChannel.close();


    }

    /**
     * 非直接缓冲区
     * 利用通道完成文件的复制
     */
    @Test
    public void test1() throws IOException {
        FileInputStream fileInputStream = new FileInputStream("D:\\1\\2.jpg");
        FileOutputStream fileOutputStream = new FileOutputStream("D:\\1\\1.jpg");

        //1获取通道
        FileChannel inputStreamChannel = fileInputStream.getChannel();
        FileChannel outputStreamChannel = fileOutputStream.getChannel();

        //2分配一个指定大小的缓冲区
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        //3读取数据，将通道中的数据存入缓冲区
        while (inputStreamChannel.read(byteBuffer) != -1) {
            //切换成读取数据的模式
            byteBuffer.flip();

            //4将缓冲区的数据写回通道
            outputStreamChannel.write(byteBuffer);

            //清空缓冲区
            byteBuffer.clear();
        }
        outputStreamChannel.close();
        inputStreamChannel.close();
        fileInputStream.close();
        fileOutputStream.close();


    }
}
